#ifndef __SCHEDULER_H
#define __SCHEDULER_H

/* processor status */
typedef struct ProcStatus_S
{
  pthread_mutex_t lock;
  pthread_barrier_t bar;
  long num_proc;
  unsigned long running;
} ProcStatus_T;
typedef ProcStatus_T * ProcStatus;

/* processor arguments */
typedef struct ProcArgs_S
{
  long tid;

#ifdef FIFO
  //Fifo * fifo;
#else
  Stack * fifo;
#endif

  ProcStatus pstat;
} ProcArgs_T;
typedef ProcArgs_T * ProcArgs;

/* work unit */
typedef struct Work_S
{
  void (*routine)(void *);
  void * input;
} Work_T;
typedef Work_T * Work;
 
/* prototypes */


void * processor (void * input);
void collectProcessors(int num_proc, pthread_t threads[], ProcStatus pstat);


#ifdef FIFO
void schedule (Fifo * f, long nt, void (*routine)(void *), void * arg);
void priSchedule (Fifo * f, long nt, void (*routine)(void *), void * arg);
void terminateProcessors (Fifo * f, int num_thread);
void launchProcessors(int num_proc, pthread_t threads[], ProcStatus pstat, ProcArgs pargs, Fifo * f);
void getWork(Fifo * q, long qid, FifoElement e);
void priGetWork(Fifo * q, FifoElement e);
#else
void schedule (Stack * f, long nt, void (*routine)(void *), void * arg);
void priSchedule (Stack * f, long nt, void (*routine)(void *), void * arg);
void terminateProcessors (Stack * f, int num_thread);
void launchProcessors(int num_proc, pthread_t threads[], ProcStatus pstat, ProcArgs pargs, Stack * f);
void getWork(Stack * q, long qid, StackElement e);
void priGetWork(Stack * q, StackElement e);
#endif

#endif
